<?php

/*
 * CopyRight  : (C)2012-2099 HaoTeam Inc.
 * Document   : EasyWeChatService.php
 * Created on : 2021-2-5 14:19:40
 * Author     : Tiger <1192851302@qq.com>
 * Description: This is NOT a freeware, use is subject to license terms.
 *              这即使是一个免费软件,使用时也请遵守许可证条款,得到当时人书面许可.
 *              未经书面许可,不得翻版,翻版必究;版权归属 HaoTeam Inc;
 */

namespace haoteam\service;

use EasyWeChat\Factory;
use app\api\model\WechatApp;
use app\api\model\WechatUser;
use app\admin\model\AdminConfig;

/**
 * 微信平台服务
 * Class EasyWeChatService
 * Tiger <1192851302@qq.com> 2021-2-5 14:19:40
 */
class EasyWeChatService {

    private static $prefix = '';
    public static $config = [
        'http' => [
            'verify' => false
        ],
        'response_type' => 'array'
    ];

    /**
     * 初始化小程序
     * @author Tiger <1192851302@qq.com>
     * @param type $mid
     * @return type
     */
    public static function miniapp($mid = 0) {
        if (empty($mid)) {
            self::$prefix = 'system_wechat_';
            $options = AdminConfig::getMore(['system_wechat_appid', 'system_wechat_appsecret', 'system_wechat_token', 'system_wechat_encodingaeskey']);
        } else {
            $options = WechatApp::getMore($mid, ['appid', 'appsecret', 'token', 'encodingaeskey']);
        }
        $config = [
            'app_id' => $options[self::$prefix . 'appid'],
            'secret' => $options[self::$prefix . 'appsecret'], // AppSecret
            'token' => $options[self::$prefix . 'token'],
            'aes_key' => $options[self::$prefix . 'encodingaeskey'], // EncodingAESKey，兼容与安全模式下请一定要填写！！！
            'log' => [
                'level' => 'debug',
                'file' => runtime_path() . '/log/wechat.log',
            ],
        ];
        return Factory::miniProgram(array_merge(self::$config, $config));
    }

    /**
     * 支付初始化
     * @author Tiger <1192851302@qq.com>
     * @param type $mid
     * @return type
     */
    public static function payment($mid = 0) {
        if (empty($mid)) {
            self::$prefix = 'system_wechat_';
            $options = AdminConfig::getMore(['system_wechat_appid', 'system_wechat_mchid', 'system_wechat_paysignkey', 'system_wechat_cert_path', 'system_wechat_key_path']);
        } else {
            $options = WechatApp::getMore($mid, ['appid', 'mchid', 'paysignkey', 'cert_path', 'key_path']);
        }

        $config = [
            'app_id' => $options[self::$prefix . 'appid'],
            'mch_id' => $options[self::$prefix . 'mchid'],
            'key' => $options[self::$prefix . 'paysignkey'], //API v2 密钥 
            'cert_path' => public_path() . $options[self::$prefix . 'cert_path'], //绝对路径
            'key_path' => public_path() . $options[self::$prefix . 'key_path'], //绝对路径
            'notify_url' => request()->domain() . '/api/wechat/callback/payment/' . $mid,
            'log' => [
                'level' => 'debug',
                'file' => runtime_path() . '/log/wechat.log',
            ],
        ];

        return Factory::payment(array_merge(self::$config, $config));
    }

    /**
     * 统一下单
     * @author Tiger <1192851302@qq.com>
     * @param type $body
     * @param type $out_trade_no
     * @param type $total_fee
     * @param type $trade_type
     * @param type $attach
     */
    public static function unify($body, $out_trade_no, $total_fee, $trade_type, $attach, &$prepayId) {
        $mid = request()->mid();
        if($mid){
            $openid = WechatUser::where('id', request()->uid())->value('openId');
        }else{
             $openid = \app\models\User::where('id', request()->uid())->value('openid');
        }
        
        $payment = self::payment($mid);
        $result = $payment->order->unify(compact('body', 'out_trade_no', 'total_fee', 'trade_type', 'openid', 'attach'));
        if (isset($result['return_code']) && $result['return_code'] == 'FAIL') {
            trace('unify|统一下单|' . json_encode($result), 'debug');
            throw new \think\Exception($result['return_msg']);
        }
        if (isset($result['result_code']) && $result['result_code'] == 'FAIL') {
            trace('unify|统一下单|' . json_encode($result), 'debug');
            throw new \think\Exception($result['err_code'] . '|' . $result['err_code_des']);
        }
        $prepayId = $result['prepay_id'];
        return $payment;
    }

    /**
     * 小程序支付
     * @author Tiger <1192851302@qq.com>
     * @param type $body
     * @param type $out_trade_no
     * @param type $total_fee
     * @return type
     */
    public static function bridgeConfig($body, $out_trade_no, $total_fee, $attach = '') {
        $prepayId = '';
        $payment = self::unify($body, $out_trade_no, ($total_fee * 100), $trade_type = 'JSAPI', $attach, $prepayId);
        return $payment->jssdk->bridgeConfig($prepayId, false);
    }

    /**
     * 退款
     * @author Tiger <1192851302@qq.com>
     * @param type $out_trade_no    商户订单号
     * @param type $out_refund_no   商户退款单号
     * @param type $total_fee       订单支付总金额
     * @param type $refund_fee      退款金额
     * @return boolean
     * @throws \think\Exception
     */
    public static function refund($out_trade_no, $out_refund_no, $total_fee, $refund_fee) {
        $payment = self::payment(request()->mid());
        $result = $payment->refund->byOutTradeNumber($out_trade_no, $out_refund_no, ($total_fee * 100), ($refund_fee * 100), [
            'notify_url' => request()->domain() . '/api/wechat/callback/refund/' . request()->mid()
        ]);
        if ($result['return_code'] == 'FAIL') {
            throw new \think\Exception($result['return_msg']);
        }
        if ($result['result_code'] == 'FAIL') {
            throw new \think\Exception($result['err_code'] . '|' . $result['err_code_des']);
        }
        return $result;
    }

    /**
     * 订阅消息【小程序】
     * @param type $mid 
     * @param type $template_id 所需下发的订阅模板id
     * @param type $touser      接收者（用户）的 openid
     * @param type $page        点击模板卡片后的跳转页面，仅限本小程序内的页面。支持带参数,（示例index?foo=bar）。该字段不填则模板无跳转。
     * @param type $data        模板内容，格式形如 { "key1": { "value": any }, "key2": { "value": any } }
     * @return type
     */
    public static function miniappAcceptMessage($mid, $template_id, $touser, $page, $data) {
        $app = self::miniapp($mid);
        return $app->subscribe_message->send(compact('template_id', 'touser', 'page', 'data'));
    }

}
